Skip to content

(Closes #2202) Update the generation of Fortran declarations to observe dependencies - #3344

Open
arporter wants to merge 57 commits into
masterfrom
2202_decln_ordering
Open

arporter wants to merge 57 commits into
masterfrom
2202_decln_ordering

Conversation

@arporter

@arporter arporter commented Feb 23, 2026 •

Copy link
Copy Markdown
Member

This is a relatively simple PR - it takes the inter-dependence handling out of _gen_param_decls and puts it into gen_decls. This also then means we can delete _gen_param_decls. I've added tests for the various tricky cases described in the original Issue and they all pass now :-)

@codecov

codecov Bot commented Feb 23, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (7762bd9) to head (8506716).

Additional details and impacted files
@@            Coverage Diff            @@
##            master     #3344   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          403       403           
  Lines        57020     57063   +43     
=========================================
+ Hits         57020     57063   +43     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@arporter

Copy link
Copy Markdown
Member Author

The NEMO ITs failed because of character variables:

Symbol Table of Container 'test_mod':
-------------------------------------
DataSymbol:
  cdwmo: DataSymbol<UnsupportedFortranType('CHARACTER(LEN = ilenwmo), DIMENSION(:), POINTER, PUBLIC :: cdwmo'), Unknown>
  ilenwmo: DataSymbol<Scalar<INTEGER, UNDEFINED>, Static, initial_value=Literal[value:'58', Scalar<INTEGER, UNDEFINED>], constant=True>

(Pdb) cdwmo = table.lookup("cdwmo")
(Pdb) cdwmo.get_all_accessed_symbols()
set()
(Pdb) cdwmo.datatype.declaration
'CHARACTER(LEN = ilenwmo), DIMENSION(:), POINTER, PUBLIC :: cdwmo'

I was proceeding to try and do something with the parse tree in UnsupportedFortranType but actually, it would probably be better to work on populating the partial_datatype in this case.

@arporter
arporter marked this pull request as draft February 24, 2026 09:05
@arporter arporter added the Blocked An issue/PR that is blocked by one or more issues/PRs. label Feb 25, 2026
@arporter

Copy link
Copy Markdown
Member Author

Marking this as blocked for the moment because I want to investigate adding support for a CharacterType with a length property.

@arporter arporter removed the Blocked An issue/PR that is blocked by one or more issues/PRs. label Apr 29, 2026
@arporter

Copy link
Copy Markdown
Member Author

Although things are now better, complex types are still a problem - I've added a (failing) test which demonstrates this.

@arporter

Copy link
Copy Markdown
Member Author

I had a problem with the UnsupportedTypes created as part of our select-type handling in the frontend. They were missing a partial_datatype so I have added that as part of this PR (to ensure we capture dependencies within their declarations).

@arporter
arporter deployed to integration October 15, 2026 09:45 — with GitHub Actions Active
@arporter

arporter commented Oct 15, 2026 •

Copy link
Copy Markdown
Member Author

Unfortunately I had several failures from the ITs, e.g. from the transmutation:

gravity_wave_drag/gw_ussp_mod.f90:28:8:

   28 |     DATA sinphi / 1, 0, -1, 0 /
      |        1
Error: DATA array ‘sinphi’ at (1) must be specified in a previous declaration

and NEMO v5:

  842 |     DATA alpham / 0.095_wp, 0.08_wp, 0.065_wp, 0.065_wp, 0.06_wp, 0.06_wp, 0.06_wp, 0.06_wp, 0.065_wp, 0.075_wp, 0.09_wp, 0.10_wp /
      |        1
Error: DATA array 'alpham' at (1) must be specified in a previous declaration

This might be hard to fix!

We have #2630 but, as Joerg says there, DATA statements with implicit loops will be a fair bit of work. For now, I could add a simple partial datatype that depends on the symbol the data statement is for?

@arporter

Copy link
Copy Markdown
Member Author

A simple partial_datatype wasn't an option as we do type checking etc. when building types. I had to make a StructureType where each component has an initial_value that is a Reference to a dependent Symbol.

@arporter
arporter deployed to integration October 15, 2026 19:47 — with GitHub Actions Active
@arporter

Copy link
Copy Markdown
Member Author

NEMOv4 IT is failing with signal 11 but I think this is ready for a first look. Functionally it is not a big change but unfortunately it touches lots of tests.
One for anyone :-)

@LonelyCat124 LonelyCat124 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arporter Implementation looks mostly good. I'm slightly concerned that ordering by variable name might make output code harder to read (than e.g. ordering by full declaration string, since that would group variables of the same type together).
Otherwise a few comments on tests/formatting.

# with case-insensitive name comparisons because the dependent symbols
# are not always created in the same scope.
local_lowered_names = [sym.name.lower() for sym in all_symbols]
decln_inputs: dict[str, set[Symbol]] = {}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't usually add type hints for variable declarations- this one has made it through. I seem to remember there was some discussion ongoing on this so I'm nmot sure if we made a decision?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's also some that have appeared in tests (so I don't forget)

if node.field.name == "f3"]) == 1
assert len([node for node in first_invoke.schedule.walk(LFRicHaloExchange)
if node.field.name == "f4"]) == 1
assert (

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you take a look at these auto-formatted (I assume) asserts? I think they're significantly more difficult to read than the old versions.

"""
for declaration in expected_declarations.splitlines():
if declaration.strip():
assert declaration in gen

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this test the ordering here any more? Or you don't think its relevant for this test as its covered elsewhere?

"STENCIL_CROSS, stencil_dofmap_type\n" in result)
assert ("use flux_direction_mod, only : x_direction, y_direction\n"
in result)
assert "integer(kind=i_def), intent(in) :: f2_extent\n" in result

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why has this been split from output3? I guess its now something like

f2_extent
f3_direction
f3_extent

? Could still have the old test with the new ordering if so.

# The order of declarations is tested separately. Compare this
# transformation's declarations as a set while preserving the exact
# order of executable statements.
# def sort_declarations(code):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these are leftover commented out code?

Comment thread src/psyclone/tests/gocean1p0_test.py Outdated
" type(r2d_field), intent(inout) :: ssh_fld\n"
" integer :: j\n"
" integer :: i\n"
" type(r2d_field), intent(inout) :: ssh_fld\n"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Has ssh_fld appeared a second timere here?

" integer(kind=i_def) :: cell\n")
assert expected in code
assert "type(field_type), intent(in) :: field1\n" in code
assert "type(field_type), intent(in) :: field2\n" in code

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do field1 and field2 no longer appear near each other in the output? If so can we test they appear next to each other as expected. If not, is it worth considering an alternative sorting of non-dependent variables, e.g. sorting by their type as it might keep the Fortran output more readable to have blocks of :

integer :: ...
integer : ....
...
type(field_type) :: ....
type(field_type) :: ....
type(field_type) :: ....

? Though I understand that it would be a pain to again change all the tests.

from psyclone.tests.lfric_build import LFRicBuild


def assert_lines_present(code, expected):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file doesn't check ordering of generated code anymore - I'm not necessarily opposed to it just wanted to check you're also ok with that (since most other files still do).

" type(field_type), intent(in) :: m1\n"
" type(field_type), intent(in) :: m2\n")
assert output in generated_code
assert all(line in generated_code for line in output.splitlines())

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also doesn't check ordering now for this test.

Comment thread pyproject.toml

[tool.ruff]
# Set the maximum line length to 79 characters
line-length = 79

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a local change for your linter?

This branch was successfully deployed

1 active (outdated) deployment
integration — 85067169 Deployed Oct 15, 2026 by arporter via build #1888
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants